package com.sgroup.studycountry.support.dto;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import com.sgroup.studycountry.support.annotation.CopyIgnore;
import com.sgroup.studycountry.support.enums.CopyIgnoreType;
import com.sun.istack.NotNull;


import java.lang.reflect.Field;
import java.lang.reflect.Type;

/**
 * Dto抽象类
 *
 * @author umi
 * @date 2021/9/22 12:12
 */
public abstract class BaseDto<T> {

    public BaseDto() {
    }

    public T convert() {
        beforeConvert();
        Class<?> genericClass = (Class<?>) this.getGenericClass();
        T entity = (T) ReflectUtil.newInstance(genericClass);
        copyFieldTo(entity, CopyIgnoreType.INSERT);
        afterConvert(entity);
        return entity;
    }

    public void convertAndUpdate(T entity) {
        beforeConvert();
        Class<?> genericClass = (Class<?>) this.getGenericClass();
        copyFieldTo(entity, CopyIgnoreType.UPDATE);
        afterConvert(entity);
    }


    private Type getGenericClass() {
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        return TypeUtil.getTypeArgument(genericSuperclass);
    }

    private void copyFieldTo(T entity, CopyIgnoreType type) {
        Field[] fields = ReflectUtil.getFields(this.getClass());
        for (Field field : fields) {
            if (!isIgnore(field, type)) {
                ReflectUtil.setFieldValue(entity, ReflectUtil.getFieldName(field), ReflectUtil.getFieldValue(this, field));
            }
        }
    }

    private boolean isIgnore(@NotNull Field field, CopyIgnoreType type) {
        CopyIgnore fieldAnnotation = field.getDeclaredAnnotation(CopyIgnore.class);
        if (fieldAnnotation == null) {
            return false;
        }
        for (CopyIgnoreType copyIgnoreType : fieldAnnotation.types()) {
            if (copyIgnoreType == type) {
                return fieldAnnotation.isIgnore();
            }
        }
        return false;
    }

    public void beforeConvert() {

    }

    public void afterConvert(T entity) {

    }

}
